// ---------------------------------------------------------------------
//
// Copyright (c) 2014 - 2019 by the IBAMR developers
// All rights reserved.
//
// This file is part of IBAMR.
//
// IBAMR is free software and is distributed under the 3-clause BSD
// license. The full text of the license can be found in the file
// COPYRIGHT at the top level directory of IBAMR.
//
// ---------------------------------------------------------------------

/////////////////////////////// INCLUDE GUARD ////////////////////////////////

#ifndef included_IBAMR_StaggeredStokesPETScVecUtilities
#define included_IBAMR_StaggeredStokesPETScVecUtilities

/////////////////////////////// INCLUDES /////////////////////////////////////

#include <ibamr/config.h>

#include "tbox/Pointer.h"

#include "petscao.h"
#include "petscvec.h"

#include <vector>

namespace SAMRAI
{
namespace hier
{
template <int DIM>
class PatchLevel;
} // namespace hier
namespace xfer
{
template <int DIM>
class RefineSchedule;
} // namespace xfer
} // namespace SAMRAI

/////////////////////////////// CLASS DEFINITION /////////////////////////////

namespace IBAMR
{
/*!
 * \brief Class StaggeredStokesPETScVecUtilities provides utility functions for
 * <A HREF="http://www.mcs.anl.gov/petsc">PETSc</A> Vec objects.
 */
class StaggeredStokesPETScVecUtilities
{
public:
    /*!
     * \name Methods acting on SAMRAI::hier::PatchLevel and
     * SAMRAI::hier::Variable objects.
     */
    //\{

    /*!
     * \brief Copy data to a parallel PETSc Vec on the provided
     * SAMRAI::hier::PatchLevel.
     */
    static void copyToPatchLevelVec(Vec& vec,
                                    int u_data_idx,
                                    int u_dof_index_idx,
                                    int p_data_idx,
                                    int p_dof_index_idx,
                                    SAMRAI::tbox::Pointer<SAMRAI::hier::PatchLevel<NDIM> > patch_level);

    /*!
     * \brief Copy data from a parallel PETSc Vec on the provided
     * SAMRAI::hier::PatchLevel.
     */
    static void copyFromPatchLevelVec(Vec& vec,
                                      int u_data_idx,
                                      int u_dof_index_idx,
                                      int p_data_idx,
                                      int p_dof_index_idx,
                                      SAMRAI::tbox::Pointer<SAMRAI::hier::PatchLevel<NDIM> > patch_level,
                                      SAMRAI::tbox::Pointer<SAMRAI::xfer::RefineSchedule<NDIM> > data_synch_sched,
                                      SAMRAI::tbox::Pointer<SAMRAI::xfer::RefineSchedule<NDIM> > ghost_fill_sched);

    /*!
     * \brief Construct a RefineSchedule to synchronize shared values that can
     * be used in conjunction with copyFromPatchLevelVec().
     *
     * \note Synchronization is not required for all data centerings.  For cases
     * in which it is not needed, this method will return a NULL pointer.
     */
    static SAMRAI::tbox::Pointer<SAMRAI::xfer::RefineSchedule<NDIM> >
    constructDataSynchSchedule(int u_data_idx,
                               int p_data_idx,
                               SAMRAI::tbox::Pointer<SAMRAI::hier::PatchLevel<NDIM> > patch_level);

    /*!
     * \brief Construct a RefineSchedule to fill ghost cell values that can be
     * used in conjunction with copyFromPatchLevelVec().
     */
    static SAMRAI::tbox::Pointer<SAMRAI::xfer::RefineSchedule<NDIM> >
    constructGhostFillSchedule(int u_data_idx,
                               int p_data_idx,
                               SAMRAI::tbox::Pointer<SAMRAI::hier::PatchLevel<NDIM> > patch_level);

    /*!
     * \brief Assign a DOF index to each unique degree of freedom on a
     * SAMRAI::hier::PatchLevel.
     *
     * The DOF indices generated by this method are compatible with the parallel
     * PETSc Vec objects generated by constructPatchLevelVec().
     *
     * \note DOF indices are \em not assigned to ghost cell values by this
     * method.
     */
    static void constructPatchLevelDOFIndices(std::vector<int>& num_dofs_per_proc,
                                              int u_dof_index_idx,
                                              int p_dof_index_idx,
                                              SAMRAI::tbox::Pointer<SAMRAI::hier::PatchLevel<NDIM> > patch_level);

    /*!
     * \brief Create an application ordering object (AO) that creates a mapping
     * between global PETSc indices and mapping of SAMRAI data indices for patch
     * data index \em dof_index_idx to a nonnegative integer \f$ (i,j,k,d):-> p \f$
     * on a SAMRAI::hier::PatchLevel.
     *
     *\see IndexUtilities::mapIndexToInteger() for
     * details on the integer mapping of SAMRAI data indices.
     *
     * \param ao_offset An integer offset used for integer mapping of SAMRAI
     * data indices.
     */
    static void constructPatchLevelAO(AO& ao,
                                      std::vector<int>& num_dofs_per_proc,
                                      int u_dof_index_idx,
                                      int p_dof_index_idx,
                                      SAMRAI::tbox::Pointer<SAMRAI::hier::PatchLevel<NDIM> > patch_level,
                                      int& u_ao_offset,
                                      int& p_ao_offset);

    //\}

protected:
private:
    /*!
     * \brief Default constructor.
     *
     * \note This constructor is not implemented and should not be used.
     */
    StaggeredStokesPETScVecUtilities() = delete;

    /*!
     * \brief Copy constructor.
     *
     * \note This constructor is not implemented and should not be used.
     *
     * \param from The value to copy to this object.
     */
    StaggeredStokesPETScVecUtilities(const StaggeredStokesPETScVecUtilities& from) = delete;

    /*!
     * \brief Assignment operator.
     *
     * \note This operator is not implemented and should not be used.
     *
     * \param that The value to assign to this object.
     *
     * \return A reference to this object.
     */
    StaggeredStokesPETScVecUtilities& operator=(const StaggeredStokesPETScVecUtilities& that) = delete;

    /*!
     * \brief Implementation of copyToPatchLevelVec() for a standard MAC
     * discretization.
     */
    static void copyToPatchLevelVec_MAC(Vec& vec,
                                        int u_data_idx,
                                        int u_dof_index_idx,
                                        int p_data_idx,
                                        int p_dof_index_idx,
                                        SAMRAI::tbox::Pointer<SAMRAI::hier::PatchLevel<NDIM> > patch_level);

    /*!
     * \brief Implementation of copyFromPatchLevelVec() for a standard MAC
     * discretization.
     */
    static void copyFromPatchLevelVec_MAC(Vec& vec,
                                          int u_data_idx,
                                          int u_dof_index_idx,
                                          int p_data_idx,
                                          int p_dof_index_idx,
                                          SAMRAI::tbox::Pointer<SAMRAI::hier::PatchLevel<NDIM> > patch_level);

    /*!
     * \brief Implementation of constructPatchLevelDOFIndices() for a standard
     * MAC discretization.
     */
    static void constructPatchLevelDOFIndices_MAC(std::vector<int>& num_dofs_proc,
                                                  int u_dof_index_idx,
                                                  int p_dof_index_idx,
                                                  SAMRAI::tbox::Pointer<SAMRAI::hier::PatchLevel<NDIM> > patch_level);
};
} // namespace IBAMR

//////////////////////////////////////////////////////////////////////////////

#endif //#ifndef included_IBAMR_StaggeredStokesPETScVecUtilities
